/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse;

import java.util.*;
import java.sql.*;

import nfse.gui.server.QueryServiceImpl;

/*******************************************************************************
 * This class runs as a thread, pulling a list of IP addresses from the
 * metadata.critical_servers table and searching the last n hours of data for
 * matching records.
 * 
 * @author bduphoff
 * 
 */
public class AutoQuery extends Thread {

    /***************************************************************************
     * When set, this attribute tells the thread when to next run.
     */
    private GregorianCalendar nextStart = null;

    /***************************************************************************
     * The number of hours to search from the run time of the process.
     */
    private final int HOURS = 24;

    /***************************************************************************
     * How frequently to run the automated search.
     */
    private final int HOUR_TO_RUN = 6;

    
    public void run() {
        while (true) {
            try {

                GregorianCalendar now = new GregorianCalendar();
                now.setTimeInMillis(System.currentTimeMillis());
                // now.set(Calendar.HOUR_OF_DAY, 0);

                boolean timeToProcess = false;

                if (nextStart != null) {

                } else {
                    nextStart = new GregorianCalendar();
                    nextStart.setTimeInMillis(now.getTimeInMillis());
                    nextStart.set(Calendar.MINUTE, 0);
                    nextStart.set(Calendar.SECOND, 0);
                    nextStart.set(Calendar.MILLISECOND, 0);
                    nextStart.set(Calendar.HOUR_OF_DAY, HOUR_TO_RUN);
                    nextStart.add(Calendar.HOUR_OF_DAY, -1 * HOURS);
                    // timeToProcess = true;
                }

                now.add(Calendar.HOUR_OF_DAY, -1 * HOURS); // Shift now back 24
                // hours
                if (now.getTimeInMillis() > nextStart.getTimeInMillis()) {
                    // 24 hours have passed, time to start again
                    timeToProcess = true;
                }

                if (timeToProcess) {

                    Timestamp startTS = new Timestamp(nextStart.getTimeInMillis());

                    nextStart.add(Calendar.HOUR_OF_DAY, HOURS);

                    Timestamp endTS = new Timestamp(nextStart.getTimeInMillis());

                    System.out.println("Searching from " + startTS + " to " + endTS + "...");

                    Class.forName("org.postgresql.Driver");

                    String url = "jdbc:postgresql://" + NetFSE.METADATA_HOST + "/" + NetFSE.METADATA_DATABASE;
                    Properties props = new Properties();
                    props.setProperty("user", NetFSE.METADATA_USER);
                    props.setProperty("password", NetFSE.METADATA_PASSWORD);
                    props.setProperty("client_encoding", "UTF8");

                    Connection metadataConnection = DriverManager.getConnection(url, props);

                    url = "jdbc:postgresql://" + NetFSE.RESULT_DB_HOST + "/" + NetFSE.RESULT_DB_DATABASE;
                    props = new Properties();
                    props.setProperty("user", NetFSE.RESULT_DB_USER);
                    props.setProperty("password", NetFSE.RESULT_DB_PASSWORD);
                    props.setProperty("client_encoding", "UTF8");

                    Connection resultConnection = DriverManager.getConnection(url, props);

                    processCriticalServers(metadataConnection, resultConnection, startTS, endTS);

                    metadataConnection.close();
                    resultConnection.close();

                    nextStart.add(Calendar.HOUR_OF_DAY, HOURS); // Advance
                    // nextStart by
                    // HOURS
                    //deleteOldStats();
                }
                sleep(60 * 5 * 1000);

            } catch (Exception E) {
                E.printStackTrace();
            }
        }
    }

    public void processCriticalServers(Connection metadataConnection, Connection resultConnection, Timestamp startTS,
            Timestamp endTS) {
        try {
            Statement resultStatement1 = resultConnection.createStatement();
            Statement resultStatement2 = resultConnection.createStatement();

            Statement metadataStatement1 = metadataConnection.createStatement();
            Statement metadataStatement2 = metadataConnection.createStatement();
            String sql = "select * from Critical_Servers";
            ResultSet rs1 = metadataStatement1.executeQuery(sql);

            QueryServiceImpl qsi = new QueryServiceImpl();

            while (rs1.next()) {
                String ip = rs1.getString("Server_IP");
                int asSrc = rs1.getInt("As_Src");
                int asDst = rs1.getInt("As_Dst");
                // String ipNote = rs1.getString("Note");
                String note = "Traffic profile for " + ip + ", " + startTS + " to " + endTS;
                String hexNote = NetFSEUtil.convertToHex(note);

                String query = "<Query>";
                if (asSrc == 1)
                    query += "<Query srcip=\"" + ip + "\"/>";
                if (asDst == 1)
                    query += "<Query dstip=\"" + ip + "\"/>";
                query += "<Timestamp start=\"" + startTS + "\"";
                if (endTS != null) {
                    query += " end=\"" + endTS + "\"";
                }
                query += "/>";
                query += "</Query>";

                int[] types = NetFSE.getTypes();
                String queryID = "";
                int count = 0;
                do {
                    Thread.sleep(10000);
                    queryID = qsi.query(query, hexNote, types, 1000000, -1);
                    // queryID = query(query, hexNote, types, -1, -1);
                    count++;
                } while (queryID.equals("failed") && count < 10);

                metadataStatement2.execute("update Critical_Servers set Query_ID='" + queryID + "', Note='" + hexNote
                        + "' where Server_IP='" + ip + "'");

                String str = NetFSEUtil.convertToHex(note.substring(0, note.indexOf(",") + 1));
                ResultSet rs2 = resultStatement1.executeQuery("select * from Queries where Note like '" + str
                        + "%' and Query_ID != '" + queryID + "' and User_ID='' limit 100000");

                while (rs2.next()) {
                    String qid = rs2.getString("Query_ID");
                    for (int i = 0; i < types.length; i++) {
                        try {
                            resultStatement2.execute("drop table " + qid + "_" + types[i]);
                        } catch (Exception E) {
                            // no op
                        }
                    }
                    try {
                        resultStatement2.execute("drop table " + qid);
                    } catch (Exception e) {

                    }
                    resultStatement2.execute("delete from Queries where Query_ID='" + qid + "'");
                    resultStatement2.execute("delete from Query_Types where Query_ID='" + qid + "'");
                }
                rs2.close();

                Thread.sleep(60000);
            }
            rs1.close();
            metadataStatement1.close();
            metadataStatement2.close();
            resultStatement1.close();
            resultStatement2.close();
            // c.close();

        } catch (Exception E) {
            E.printStackTrace(System.out);
        }
    }

}
